package com.eolwral.osmonitor;

import com.eolwral.osmonitor.preferences.Preferences;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
/*import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;*/
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.text.Html;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.TextView;

public class CpuInfo extends Activity
{
	private int RefreshInterval;
	private boolean UseCelsius;
	
	private class CpuInfoRunnableType implements Runnable
	{
		public CpuInfoRunnableType()
		{
			ScalingMinFreqTxt = (TextView)findViewById(R.id.ScalingFreqMin);
			ScalingMaxFreqTxt = (TextView)findViewById(R.id.ScalingFreqMax);
			ScalingCurrFreqTxt = (TextView)findViewById(R.id.ScalingFreqCurr);
			ScalingGovernorTxt = (TextView)findViewById(R.id.CpuGovernorTxt);
			TemperatureTxt = (TextView)findViewById(R.id.CpuTemperature);
			CpuCoresTxt = (TextView)findViewById(R.id.CpuCoresEnabled);
			ActiveGroupTxt = (TextView)findViewById(R.id.ActiveGroupText);
			IOSchedulerTxt = (TextView)findViewById(R.id.IoSchedulerText);
			
			TextView[] transitionsText = {
					(TextView)findViewById(R.id.TransitionsCpu1),
					(TextView)findViewById(R.id.TransitionsCpu2),
					(TextView)findViewById(R.id.TransitionsCpu3),
					(TextView)findViewById(R.id.TransitionsCpu4),
					(TextView)findViewById(R.id.TransitionsLp)
			};
			
			TextView[] activeTimeText = {
					(TextView)findViewById(R.id.ActiveTimeCpu1),
					(TextView)findViewById(R.id.ActiveTimeCpu2),
					(TextView)findViewById(R.id.ActiveTimeCpu3),
					(TextView)findViewById(R.id.ActiveTimeCpu4),
					(TextView)findViewById(R.id.ActiveTimeLp)
			};
			
			TextView[] transitionsDeltaText = {
					(TextView)findViewById(R.id.TransitionDeltaCpu1),
					(TextView)findViewById(R.id.TransitionDeltaCpu2),
					(TextView)findViewById(R.id.TransitionDeltaCpu3),
					(TextView)findViewById(R.id.TransitionDeltaCpu4),
					(TextView)findViewById(R.id.TransitionDeltaLp)
			};
			
			TransitionsText = transitionsText;
			ActiveTimeText = activeTimeText;
			TransitionsDeltaText = transitionsDeltaText;
			
			((TextView)findViewById(R.id.FreqMin)).setText(Integer.toString(CpuStat.GetCpuMinFreq(0)));
			((TextView)findViewById(R.id.FreqMax)).setText(Integer.toString(CpuStat.GetCpuMaxFreq(0)));
			if (!CpuStat.Tegra3IsTegra3())
			{
				findViewById(R.id.CpuTegra3CoresEnabledRow).setVisibility(View.GONE);
				findViewById(R.id.CpuTegra3ActiveGroupRow).setVisibility(View.GONE);
				findViewById(R.id.CpuTegra3HotplugTransitionsTable).setVisibility(View.GONE);
			}
			else if (CpuStat.Tegra3GetActiveCpuGroup() == null)
			{
				findViewById(R.id.CpuTegra3ActiveGroupRow).setVisibility(View.GONE);
			}
		}

		/* TODO: Not yet implemented.
		private String SensorName = "";
		private float SensorTemp = 0;
		
		private SensorEventListener SensorListener = new SensorEventListener() {
			@Override
			public void onAccuracyChanged(Sensor sensor, int accuracy) {
			}

			@Override
			public void onSensorChanged(SensorEvent event) {
				SensorName = event.sensor.getName().replace("sensor", "");
				SensorTemp = event.values[0];
			}
		};*/

		public void run()
		{
			ScalingMinFreqTxt.setText(Integer.toString(CpuStat.GetCpuMinScalingFreq(0)));
			ScalingMaxFreqTxt.setText(Integer.toString(CpuStat.GetCpuMaxScalingFreq(0)));

			{
				StringBuilder freqStr = new StringBuilder();
				ProcStat.Update();
				int[] freq = ProcStat.GetCPUScalingFreq();
				
				for (int i = 0; i < freq.length; ++i)
				{
					int cpuFreq = freq[i];
					int preCpuFreq = PreCPUFreq[i];
					if (cpuFreq != 0)
					{
						if (i != 0)
							freqStr.append(" / ");
					
						if (cpuFreq > preCpuFreq)
							freqStr.append("<font color=red>" + cpuFreq + "</font>");
						else if (cpuFreq < preCpuFreq)
							freqStr.append("<font color=green>" + cpuFreq + "</font>");
						else
							freqStr.append(cpuFreq);
					}
					
					PreCPUFreq[i] = cpuFreq;
				}
				
				ScalingCurrFreqTxt.setText(Html.fromHtml(freqStr.toString()));
			}
			
			ScalingGovernorTxt.setText(CpuStat.GetCpuGovernor(0));

			java.text.DecimalFormat TempFormat = new java.text.DecimalFormat("#.##");
			float temperature = CpuStat.GetCpuTemperature(); 
			if (!Float.isNaN(temperature))
			{
				String text = UseCelsius ?
					TempFormat.format(temperature) + "°C" :
					TempFormat.format(temperature * 9 / 5 + 32) + "°F";
				TemperatureTxt.setText(text);
			}
			
			/* TODO: This is not implemented yet.
			else if (SensorTemp != 0)
				m_ProcessorTempStr.append("<br />"+SensorName+"<br />")
				.append("&nbsp;&nbsp;&nbsp;&nbsp<b>"+SensorTemp+"°C")
				.append(" ("+TempFormat.format(SensorTemp*9/5+32)+"°F)</b>");*/

			boolean isTegra3 = CpuStat.Tegra3IsTegra3();
			if (isTegra3)
			{
				CpuCoresTxt.setText(Integer.toString(CpuStat.Tegra3GetEnabledCoreCount()));
				ActiveGroupTxt.setText(
						ProcStat.Tegra3GetIsLowPowerClusterActive() ?
							R.string.cpu_tegra3activegroup_lowpower_text :
							R.string.cpu_tegra3activegroup_generic_text);
			}

			IOSchedulerTxt.setText(IOStat.GetActiveScheduler());

			if (isTegra3)
			{
				//Get the hotplug statistics.
				CpuStat.Tegra3CpuStat[] statistics = CpuStat.Tegra3GetHotplugStatistics();
				
				for (int i = 0, j = Math.min(statistics.length, TransitionsText.length); i < j; ++i)
				{
					TransitionsText[i].setText(Integer.toString(statistics[i].GetTransitions()));
					ActiveTimeText[i].setText(Integer.toString(statistics[i].GetActiveTime()));
					if (LastStatistics != null)
					{
						int transitionsDelta = statistics[i].GetTransitions() - LastStatistics[i].GetTransitions();
						if (transitionsDelta != 0)
							TransitionsDeltaText[i].setText(Integer.toString(transitionsDelta));
						else
							TransitionsDeltaText[i].setText("");
					}
				}
				LastStatistics = statistics;
			}
			
			schedule();
		}
		
		private void schedule()
		{
			CpuInfoHandler.postDelayed(this, RefreshInterval);
		}
		
		private TextView ScalingMinFreqTxt;
		private TextView ScalingMaxFreqTxt;
		private TextView ScalingCurrFreqTxt;
		private TextView ScalingGovernorTxt;
		private TextView TemperatureTxt;
		private TextView CpuCoresTxt;
		private TextView ActiveGroupTxt;
		private TextView IOSchedulerTxt;
		
		private TextView[] TransitionsText;
		private TextView[] ActiveTimeText;
		private TextView[] TransitionsDeltaText;
		
		private int[] PreCPUFreq = new int[CpuStat.GetCpuCount()];
		private CpuStat.Tegra3CpuStat[] LastStatistics;
	};
	
	/**
	 * Gets the CPU Frequency scaling list, in user-readable form.
	 * 
	 * @return An array of strings. The indices corresponds to the indices returned
	 *         by CpuStat.GetCpuScalingFreqList()
	 */
	public static String[] getCpuScalingFreqList()
	{
		final int[] cpuFreqList = CpuStat.GetCpuScalingFreqList(); 
		final String[] result = new String[cpuFreqList.length];
		for (int i = 0, j = cpuFreqList.length; i < j; ++i)
			result[i] = (cpuFreqList[i] / 1000) + " MHz";
		
		return result;
	}
	
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.cpu_info_layout);
		CpuInfoRunnable = new CpuInfoRunnableType();
		GestureScroller = new GestureScroller(this, findViewById(R.id.CpuInfo), 1);

		//Register the event handlers
		final int[] cpuFreqList = CpuStat.GetCpuScalingFreqList(); 
		final String[] cpuStrFreqList = CpuInfo.getCpuScalingFreqList();
		((ImageButton)findViewById(R.id.btnCpuMin)).setOnClickListener(new OnClickListener()
		{
			public void onClick(View v)
			{
				if (cpuFreqList.length == 0)
					return;

				int curFreq = 0;
				for (curFreq = 0; curFreq < cpuFreqList.length; curFreq++)
				{
					if (cpuFreqList[curFreq] == CpuStat.GetCpuMinScalingFreq(0))
						break;
				}

				AlertDialog.Builder SetCPUMinBox = new AlertDialog.Builder(CpuInfo.this);
				SetCPUMinBox.setSingleChoiceItems(cpuStrFreqList, curFreq, new DialogInterface.OnClickListener() 
					{
						public void onClick(DialogInterface dialog, int item) 
						{
							if (!getRooted())
							{
								dialog.dismiss();
								return;
							}

							StringBuilder SetCPUCmd = new StringBuilder();
							if (cpuFreqList[item] <= CpuStat.GetCpuMaxScalingFreq(0) && getRooted())
							{
								SetCPUCmd.append("echo ");
								SetCPUCmd.append(cpuFreqList[item]);
								SetCPUCmd.append(" > /sys/devices/system/cpu/cpu");
								SetCPUCmd.append(0);
								SetCPUCmd.append("/cpufreq/scaling_min_freq");
								SetCPUCmd.append("\n");

								CommonUtil.execCommand(SetCPUCmd.toString());
							}
							dialog.dismiss();
						}
					}
				);

				AlertDialog SetCPUMin = SetCPUMinBox.create();
				SetCPUMin.show();
			}
		});

		((ImageButton)findViewById(R.id.btnCpuMax)).setOnClickListener(new OnClickListener()
		{
			public void onClick(View v) {
				if (cpuFreqList.length == 0)
					return;

				int curFreq = 0;
				for (curFreq = 0; curFreq < cpuFreqList.length; curFreq++)
				{
					if (cpuFreqList[curFreq] == CpuStat.GetCpuMaxScalingFreq(0))
						break;
				}

				AlertDialog.Builder SetCPUMaxBox = new AlertDialog.Builder(CpuInfo.this);
				SetCPUMaxBox.setSingleChoiceItems(cpuStrFreqList, curFreq, new DialogInterface.OnClickListener() 
					{
						public void onClick(DialogInterface dialog, int item) 
						{
							if (!getRooted())
							{
								dialog.dismiss();
								return;
							}

							StringBuilder SetCPUCmd = new StringBuilder();
							if (cpuFreqList[item] >= CpuStat.GetCpuMinScalingFreq(0) && getRooted())
							{
								SetCPUCmd.append("echo ");
								SetCPUCmd.append(cpuFreqList[item]);
								SetCPUCmd.append(" > /sys/devices/system/cpu/cpu");
								SetCPUCmd.append(0);
								SetCPUCmd.append("/cpufreq/scaling_max_freq");
								SetCPUCmd.append("\n");

								CommonUtil.execCommand(SetCPUCmd.toString());
							}
							dialog.dismiss();
						}
					}
				);

				AlertDialog SetCPUMax = SetCPUMaxBox.create();
				SetCPUMax.show();
			}
		});

		((ImageButton)findViewById(R.id.btnCpuGov)).setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				final String[] CPUGovList = CpuStat.GetCpuGovernorList();
				if (CPUGovList == null)
					return;

				int CurGov = 0;
				for(CurGov = 0; CurGov < CPUGovList.length; ++CurGov)
				{
					if (CPUGovList[CurGov].equals(CpuStat.GetCpuGovernor(0)))
						break;
				}

				AlertDialog.Builder SetCpuGovBox = new AlertDialog.Builder(CpuInfo.this);
				SetCpuGovBox.setSingleChoiceItems(CPUGovList, CurGov, new DialogInterface.OnClickListener() 
					{
						public void onClick(DialogInterface dialog, int item) 
						{
							if (!getRooted())
							{
								dialog.dismiss();
								return;
							}

							String SetCPUCmd = "";
							if (getRooted())
							{
								SetCPUCmd = "echo " + CPUGovList[item] +
										" > /sys/devices/system/cpu/cpu" + 0 + "/cpufreq/scaling_governor"+"\n";
								CommonUtil.execCommand(SetCPUCmd);
							}
							dialog.dismiss();
						}
					}
				);

				AlertDialog SetCPUMax = SetCpuGovBox.create();
				SetCPUMax.show();
			}
		});

		((ImageButton)findViewById(R.id.btnCpuCores)).setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				AlertDialog.Builder SetCoresMaxBox = new AlertDialog.Builder(CpuInfo.this);

				int maxCores = 4;
				String[] cores = new String[maxCores];
				for (int i = 0; i < maxCores; ++i)
					cores[i] = Integer.toString(i + 1);

				SetCoresMaxBox.setSingleChoiceItems(cores, CpuStat.Tegra3GetEnabledCoreCount() - 1, new DialogInterface.OnClickListener() 
					{
						public void onClick(DialogInterface dialog, int item) 
						{
							if (!getRooted())
							{
								dialog.dismiss();
								return;
							}

							String SetCoresCmd = "echo " + Integer.toString(item + 1) +
									" > /sys/kernel/debug/tegra_hotplug/max_cpus" + "\n";
							CommonUtil.execCommand(SetCoresCmd);
							dialog.dismiss();
						}
					}
				);

				AlertDialog SetCPUMax = SetCoresMaxBox.create();
				SetCPUMax.show();
			}
		});
	}
	
	public boolean onCreateOptionsMenu(Menu optionMenu) 
	{
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item)
	{
		super.onOptionsItemSelected(item);
		return true;
	}

	@Override
	public void onPause() 
	{
		/* TODO: Not implemented yet.
		SensorManager SMer = (SensorManager) getSystemService(SENSOR_SERVICE);
    	Sensor TempSensor = SMer.getDefaultSensor(Sensor.TYPE_TEMPERATURE);
    	if(SMer != null  && TempSensor != null)
    		SMer.unregisterListener(SensorListener, TempSensor);*/
		CpuInfoHandler.removeCallbacks(CpuInfoRunnable);
		super.onPause();
	}
	
	@Override
	protected void onResume() 
	{
		RestorePrefs();
		CpuInfoHandler.post(CpuInfoRunnable);
		
		/* TODO: Not implemented yet.
		SensorManager SMer = (SensorManager) getSystemService(SENSOR_SERVICE);
		Sensor TempSensor = SMer.getDefaultSensor(Sensor.TYPE_TEMPERATURE);
		if(SMer != null && TempSensor != null)
			SMer.registerListener(SensorListener, TempSensor, SensorManager.SENSOR_DELAY_UI);*/
		super.onResume();
	}
	
	protected void onActivityResult(int requestCode, int resultCode, Intent data)
	{
		RestorePrefs();
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent me)
	{
		return GestureScroller.onTouchEvent(me);
	}

	private void RestorePrefs()
	{
		SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
		try
		{
			RefreshInterval = Integer.parseInt(settings.getString(Preferences.PREF_UPDATE, "2")) * 1000;
			UseCelsius = settings.getBoolean(Preferences.PREF_TEMPERATURE, true);
		}
		catch(Exception e)
		{
		}
	}
	
	private Boolean getRooted()
	{
		SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
		return settings.getBoolean(Preferences.PREF_ROOTED, false);
	}

	private CpuInfoRunnableType CpuInfoRunnable;
	private Handler CpuInfoHandler = new Handler();
	
	private GestureScroller GestureScroller;
}
